//SamXIAO
#include <bits/stdc++.h>
using namespace std;

int a[1000][1000] = {{1, 2}, {2, 1}};

void getans(int m) {
   int n = 2;
   for (int i = 1; i < m; i++) {
      for (int j = 0; j < n; j++) {
         for (int k = 0; k < n; k++) {
            a[j][k + n] = a[j][k] + n;
            a[j + n][k] = a[j][k] + n;
            a[j + n][k + n] = a[j][k];
         }
      }
      n *= 2;
   }
}

int pw2(int n) {
   int x = 1;
   while (n--) x *= 2;
   return x;
}

void output(int n) {
   for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
         printf("%d%s", a[i][j], j == n - 1 ? "\n" : " ");
      }
   }
}

void work1() {
   int m;
   scanf("%d", &m);
   getans(m);
   output(pw2(m));
}

//递归实现
void dg(int m) {
   if (0 == m) {
      a[0][0] = 1;
      return;
   }
   int n = pw2(m - 1);
   dg(--m);
   for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
         a[i][j + n] = a[i][j] + n;
         a[i + n][j] = a[i][j] + n;
         a[i + n][j + n] = a[i][j];
      }
   }
}

void work2() {
   int m;
   scanf("%d", &m);
   dg(m);
   output(pw2(m));
}

int main() {
   work2();
   return 0;
}
